/*
 * Copyright (C) 2010-2011 Graz University of Technology, Austria. All Rights reserved. 
 *
 * Contact: Simone Kopeinik <simone.kopeinik@tugraz.at>
 * 	   Graz University of Technology, Knowledge Management Institute, Brückenkopfgasse 1/6, 8020 Graz 	
 * 	   <http://www.kmi.tugraz.at/>
 * 
 * This software is part of the TARGET platform developed by the
 * TARGET EC-funded project www.reachyourtarget.org
 *
 * This software is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * The GNU General Public License is available at <http://www.gnu.org/licenses/>.
 *
 */
package at.tugraz.kmi.css.cbkst2.prereq.io;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.logging.Logger;

import org.apache.commons.collections15.BidiMap;

import at.tugraz.kmi.css.cbkst2.CbKSTCompetence;
import at.tugraz.kmi.css.cbkst2.CbKSTVertex;
import at.tugraz.kmi.css.cbkst2.ImmutablePrerequesiteOrderSet;
import at.tugraz.kmi.css.cbkst2.PERSISTENCE_TYPE;
import at.tugraz.kmi.css.cbkst2.PrerequesiteOrderSet;
import at.tugraz.kmi.css.cbkst2.PrerequesiteRelation;
import at.tugraz.kmi.css.cbkst2.StructureLoader;
import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
import cern.colt.matrix.DoubleMatrix2D;
import cern.colt.matrix.impl.SparseDoubleMatrix2D;

import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provider;

import edu.uci.ics.jung.algorithms.util.Indexer;

/**
 * A CSV IO plugin for reading and writing {@link PrerequesiteOrderSet}'s.
 * 
 * @author Georg Öttl <georg.oettl@gmail.com>
 * 
 */
public final class CSVSkillStructureIO extends StructureLoader<CbKSTCompetence> {

	private static final char										SEPERATOR_CHAR	= ';';

	private final Provider<PrerequesiteOrderSet<CbKSTCompetence>>	orderedSetProvider;

	private final Logger											log;

	@Inject
	CSVSkillStructureIO(
			Provider<PrerequesiteOrderSet<CbKSTCompetence>> orderedSetProvider,
			Logger log) {
		this.orderedSetProvider = orderedSetProvider;
		this.log = log;

	}

	@Override
	public PrerequesiteOrderSet<CbKSTCompetence> readStructure(Reader inputData)
			throws IOException {
		try {
			log.info("Reading CSV Structure");
			CSVReader csvReader = new CSVReader(inputData, SEPERATOR_CHAR);
			String[] header = csvReader.readNext();
			int N = header.length;
			CbKSTCompetence[] skills = new CbKSTCompetence[N];
			PrerequesiteOrderSet<CbKSTCompetence> graph = orderedSetProvider
					.get();
			// Adding all vertices with their names;
			for (int i = 1; i < N; i++) {
				skills[i - 1] = new CbKSTCompetence(header[i]);
				graph.add(skills[i - 1]);
			}

			int row = 0;
			String[] nextLine = csvReader.readNext();
			while (nextLine != null) {

				for (int column = 1; column < N; column++) {
					double d = Double.valueOf(nextLine[column]);
					if (d != 0) {
						graph.addPrerequesite(PrerequesiteRelation.of(
								skills[row], skills[column - 1]));
					}
				}
				row++;
				nextLine = csvReader.readNext();
			}
			return graph;
		} finally {
			inputData.close();
		}

	}

	@Override
	public void writeStructure(
			ImmutablePrerequesiteOrderSet<CbKSTCompetence> graphAdapter,
			Writer writer) throws IOException {
		log.info("Writing CSV Structure");
		try {
			int numVertices = graphAdapter.getCbKSTVertices().size();
			SparseDoubleMatrix2D matrix1 = new SparseDoubleMatrix2D(
					numVertices, numVertices);

			BidiMap<CbKSTCompetence, Integer> indexer = Indexer
					.<CbKSTCompetence> create(graphAdapter.getCbKSTVertices());
			int i1 = 0;
			CSVWriter csvWriter = new CSVWriter(writer, SEPERATOR_CHAR);

			Collection<CbKSTCompetence> vertices = graphAdapter
					.getCbKSTVertices();
			if (vertices != null) {
				for (CbKSTCompetence v : vertices) {
					ImmutableSet<CbKSTCompetence> outEdges = graphAdapter
							.getDescendants(v);
					if (outEdges != null) {
						for (CbKSTVertex w : outEdges) {
							int j1 = indexer.get(w);
							matrix1.set(i1, j1, matrix1.getQuick(i1, j1) + 1.0);
						}
					}
					i1++;
				}
			}
			DoubleMatrix2D matrix = matrix1;
			int N = matrix.columns();
			String[] columns = new String[N + 1];
			for (int i = 0; i < N; i++) {
				columns[i + 1] = indexer.getKey(i).getId();
			}
			csvWriter.writeNext(columns);
			for (int r = 0; r < N; r++) {
				String[] rowArray = new String[N + 1];
				rowArray[0] = indexer.getKey(r).getId();
				for (int c = 0; c < N; c++) {
					rowArray[c + 1] = String.valueOf(matrix.getQuick(r, c));

				}
				csvWriter.writeNext(rowArray);
				csvWriter.flush();
			}
			csvWriter.close();
		} catch (Exception e) {
			throw new RuntimeException("Error saving:", e);
		}
	}

	@Override
	public PERSISTENCE_TYPE type() {
		return PERSISTENCE_TYPE.csv;
	}

}
